<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div class = "btn1">按钮</div>
<div class = "btn2">停</div>
<script>
    /*
    * js运行机制：代码是怎么执行的 执行的顺序是什么 ？
    *   按顺序从上往下去执行
    *   console.log(1)
    *   console.log(2)
    *
    * 所以，但凡上面的代码没有执行完，下面的代码就不能执行
    *
    * 1.同步代码：按顺序依次去执行（几乎所有的代码都是同步代码）
    *   当同步代码没有执行完的时候，执行任何操作都是无效的，必须要等同步代码执行完
    * let div = document.querySelector("div")
    *
    * div.onclick = function(){
    *   console.log("点击了")
    * }
    *
    * for(let i = 0;i < 10000000;i++){
    *
    * }
    *
    * console.log(2)
    * //以上这四段同步代码，必须全部都执行完，才能执行其他操作，比如点击事件，必须等到最后的打印2这段代码执行完，点击才能接着在其后面执行出来
    *
    *
    * 2.异步代码：执行是完全脱离了同步代码的范围，单独执行的
    *   异步代码只有几种：
    *       事件也是异步代码，什么点击事件等等
    *
    *       定时器：规定了某一个时刻之后再去执行的代码，定时器
    *
    *       第一种定时器，延时定时器setTimeout(本身是一个函数)：规定某段时间之后执行
    *           接收的参数：两个参数，1是需要等待被执行的代码内容，即回调函数；2是等待的时间（数字形式）,时间单位ms，1000ms = 1s
    *       返回值:setTimeout执行之后，会返回定时器的编号，就是一个数字，可以用变量存储
    *       例如：setTimeout(()=>{}) //会返回数字11
    *
    * 同步代码和异步代码的关系：
    *   无论代码的书写顺序如何 js执行永远是 同步代码执行完 异步代码才执行
    *
    * 异步代码存放的位置：
    *   同步代码和异步代码都存放在调用栈中：可以将两者看成是分别不同的两个队伍，其中同步代码是VIP通道队伍
    *
    * */

    /*setTimeout(function (){
        console.log("银时牛逼")
    },0) //这里传了一个参数函数表达式，另一个参数0毫秒，规定了0秒之后打印
    //以上这个函数是异步代码，还没执行或者正在执行都不会不会影响后续代码的执行进程
    //以下四段代码都是同步代码，同步代码之内的代码需要依次执行完才能执行下一个
    let div = document.querySelector("div")

    div.onclick = function(){
        console.log("点击了")
    }

    for(let i = 0;i < 10000;i++){

    }

    console.log(2)
    console.log("同步代码最后一句")
    //以上代码中，哪怕异步代码中的定时器设置0毫米之后，异步代码写在同步代码之前，它也必须等待后面的所有同步代码执行完了，才能执行异步代码中设置的0毫米定时器
    //所以最后的打印顺序是先打印2 再打印同步代码最后一句 如果在同步代码执行是还顺带点击了按钮会打印点击了 最后才打印银时牛逼
    */

    /*
    * 异步代码的特点：
    *   1.完全不阻塞页面的渲染和js代码的执行
    *   2.可以修改代码的执行顺序，以前只能从上往下执行，现在可以通过一般代码让执行顺序发生改变，形成优先顺序
    *
    * */
    /*setTimeout(function (){
        console.log("第一段执行")
    },2000)
    setTimeout(function (){
        console.log("第二段执行")
    },0)*/
    //这里两个异步代码站在同一条起跑线上（同步代码执行完的那一瞬），异步代码按设置时间的先后顺序进行执行，虽然第一段写在前面，但时间比第二段要慢
    /*
    //经典的 定时器的面试题：使用for循环实现 每隔一秒 打印数组里面的每一项
    let arr = [1,2,3,4]
    //以下代码有两个错误
    //for(let i = 0;i < arr.length;i++){
    //    setTimeout(function (){//这是异步代码会在循环执行完之后才执行，循环之后i变成了4（下标），数组里面下标为4的内容不存在 所以访问不到
    //        console.log(arr[i])
    //    },1000)//这里的一秒不是每隔一秒，而是异步代码中所有的内容都在等待同步代码执行完之后的那一秒全部一起执行
    //}
    //1.让arr[i]能正确访问 用var会有作用域的问题 可以用闭包解决 用let是在回避这个问题
    //2.让 打印顺序和内容 能正确符合要求
    //for(let i = 0;i < arr.length;i++){
    //    setTimeout(function (){
    //        console.log(arr[i])
    //    },1000 * i + 1000)//加1000是因为i是从0开始，所以要加1秒来补上误差
    //}
    for(var i = 0;i < arr.length;i++){
        setTimeout((function (i){ //这个立执行函数的i接收每次实参传入的i的值
            return function (){
                console.log(arr[i]) //这里面函数的i会优先在自己里面去寻找变量i，找不到再去外面一层一层的寻找，因为自己没有，就去找外面立执行函数的i
                //每次外面立执行函数的形参i的值都会被这里面函数的i所接收，所以每次找到的就是各自的i了
            }
        })(i),1000 * i + 1000) //实参i每次循环将外面的i的值接收，传入给里面的形参i
    }*/

    /*
    * 定时器清除：
    *   clearTimeout() 是一个函数，需要加括号去执行
    *
    *   clearTimeout接收一个参数：定时器的编号
    *
    * */
    //设置一个按钮，点击之后五秒爆炸
    let btn1 = document.querySelector(".btn1")
    let btn2 = document.querySelector(".btn2")
    let timer = null //在全局声明一个不存在的编号占位 如果在setTimeout函数里面声明就没法从外部访问
    btn1.onclick = function (){
        console.log("炸弹被激活，五秒之后爆炸!")
        timer = setTimeout(function (){
            console.log("boom!")
        },5000)
    }
    btn2.onclick = function (){
        console.log("炸弹已经清除")
        clearTimeout(timer)
    }


</script>
</body>
</html>